package com.arguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.arguigu.gmall.order.mapper.CartInfoMapper;
import com.arguigu.gmall.order.mapper.OrderDetailMapper;
import com.arguigu.gmall.order.mapper.OrderInfoMapper;
import com.arguigu.gmall.order.service.OrderInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.mq.constants.MqConst;
import com.atguigu.gmall.mq.service.RabbitService;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @author Administrator
 * @create 2020-05-28 10:14
 */
public class OrderInfoServiceImpl implements OrderInfoService {

    @Value("${ware.url}")
    private String wareUrl;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitService rabbitService;
    //校验库存
    @Override
    public boolean hasStock(Long skuId, Integer skuNum) {
        String result = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        return "1".equals(result);
    }

    //保存订单
    //        3、保存订单   订单表、订单详情表
    //        4、购买了商品从购物车中删除出去
    @Override
    public Long submitOrder(OrderInfo orderInfo) {
        //一：订单表

        //订单状态：为支付
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        //第三方支付交易号
        String outTradeNo = "ATGUIGU" + System.currentTimeMillis();
        Random random = new Random();
        for(int i=0;i<10;i++){
            outTradeNo += random.nextInt(10);
        }
        orderInfo.setOutTradeNo(outTradeNo);

        //交易体
        String tradeBody="";
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList){
            tradeBody += orderDetail.getSkuName()+"";
            //订单详情的价格重新查询一次  校验价格 查询真实价格
            orderDetail.setOrderPrice(productFeignClient.getSkuPrice(orderDetail.getSkuId()));
        }
        orderInfo.setTradeBody(tradeBody);
        //总金额 需要重新计算：不能使用页面上计算好的数据
        orderInfo.sumTotalAmount();
        //时间
        orderInfo.setCreateTime(new Date());
        //进度状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());//未支付
        //订单的图片
        //orderInfo.setImgUrl();
        //保存订单
        orderInfoMapper.insert(orderInfo);

//二：订单详情表
        //String cartKey = cacheCartKey(String.valueOf(orderInfo.getUserId()));
        orderDetailList.forEach(orderDetail -> {
            //外键
            orderDetail.setOrderId(orderInfo.getId());
            orderDetailMapper.insert(orderDetail);
            //3:删除已经购买了商品的购物车   用户ID  SkuId  缓存
            /*cartInfoMapper.delete(new QueryWrapper<CartInfo>()
            .eq("user_id",orderInfo.getUserId())
            .eq("sku_id",orderDetail.getSkuId()));
            redisTemplate.opsForHash().delete(cartKey,orderDetail.getSkuId().toString());*/
        });

        //发送延迟消息 为了用户2小时不买单而取消订单
        //发延迟消息  为了用户不买单的时候  2小时之内  取消此订单
//        rabbitService.sendDelayedMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL
//        ,MqConst.ROUTING_ORDER_CANCEL,orderInfo.getId(),MqConst.DELAY_TIME*1000);
        //测试
        rabbitService.sendDelayedMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL
       ,MqConst.ROUTING_ORDER_CANCEL,orderInfo.getId(),10000);

        return orderInfo.getId();
    }

    //取消订单
    @Override
    public void cancelOrder(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        //1.查询订单状态 必须是未支付的
        if(OrderStatus.UNPAID.name().equals(orderInfo.getOrderStatus())){
            //2.取消
            orderInfo.setOrderStatus(OrderStatus.CLOSED.name());
            //进度
            orderInfo.setProcessStatus(ProcessStatus.CLOSED.name());
            orderInfoMapper.updateById(orderInfo);
        }

    }

    //查询订单对象
    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        //订单详情 使用订单ID 作为外键
        List<OrderDetail> orderDetailList = orderDetailMapper.
                selectList(new QueryWrapper<OrderDetail>().eq("order_id", orderId));
        orderInfo.setOrderDetailList(orderDetailList);
        return orderInfo;
    }

    //更新订单状态和进度状态
    @Override
    public void updateOrderStatus(Long orderId, OrderStatus os, ProcessStatus ps) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        orderInfo.setOrderStatus(os.name());
        orderInfo.setProcessStatus(ps.name());
        orderInfoMapper.updateById(orderInfo);
    }

    //更新订单进度状态
    public void updateOrderStatus(Long orderId, ProcessStatus ps) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        orderInfo.setProcessStatus(ps.name());
        orderInfoMapper.updateById(orderInfo);
    }
    //发消息到库存微服务 扣减库存
    @Override
    public void sendOrderStatus(Long orderId) {
        //1.更新订单进度状态 --> 已通知仓库
        this.updateOrderStatus(orderId,ProcessStatus.NOTIFIED_WARE);
        //初始化一份数据,发消息给库存微服务
        String resultString = initWareOrder(orderId);
        //3.发消息给库存微服务  (请查看库存微服务Api文档）
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK,
                MqConst.ROUTING_WARE_STOCK,resultString);
        //减库存不用写，写好了
    }

    public String initWareOrder(Long orderId){
        //1.查询该订单
        OrderInfo orderInfo = this.getOrderInfo(orderId);
        //2.将该订单的信息转化为仓库需要的数据，使用JSON串
        Map<String, Object> resultMap = this.initWareOrder(orderInfo);
        return JSONObject.toJSONString(resultMap);
    }
    //初始化点单数据，
    public Map<String,Object> initWareOrder(OrderInfo orderInfo){
      Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("orderId",orderInfo.getId());                     //订单id
        resultMap.put("consignee",orderInfo.getConsignee());            //收货人
        resultMap.put("consigneeTel",orderInfo.getConsigneeTel());      //收件人电话
        resultMap.put("orderComment",orderInfo.getOrderComment());      //订单备注
        resultMap.put("orderBody",orderInfo.getTradeBody());            //订单描述(第三方支付用)
        resultMap.put("deliveryAddress",orderInfo.getDeliveryAddress());//送货地址
        resultMap.put("paymentWay","2");                                //

        resultMap.put("wareId",orderInfo.getWareId());     //仓库编号

        //订单详情
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if (!CollectionUtils.isEmpty(orderDetailList)){
            List<Map> mapList = orderDetailList.stream().map(orderDetail -> {
                Map map = new HashMap<>();
                map.put("skuId", orderDetail.getSkuId());
                map.put("skuNum", orderDetail.getSkuNum());
                map.put("skuName", orderDetail.getSkuName());
                return map;
            }).collect(Collectors.toList());
            resultMap.put("details",mapList);
        }
        return resultMap;
    }

    //拆分订单
    @Override
    public List<OrderInfo> orderSplit(String orderId, String wareSkuMap) {
       //1.获取要拆分的订单
        OrderInfo orderInfoOrigin = this.getOrderInfo(Long.parseLong(orderId));
        //2.开始拆分 wareSkuMap:[{"wareId":"1","skuIds":["14"]},{"wareId":"2","skuIds":["1"]}]
        List<Map> wareSkuMapList = JSONObject.parseArray(wareSkuMap, Map.class);
        //拆单后订单集合
        List<OrderInfo> orderInfoList = new ArrayList<>();

        //  仓库的ID      库存IDS
        //{"wareId":"1","skuIds":["14,15"]}
        for (Map wareMap: wareSkuMapList){
            //订单表
            OrderInfo subOrderInfo = new OrderInfo();
            //3.9成相似：将原始订单表复制给子订单
            BeanUtils.copyProperties(orderInfoOrigin,subOrderInfo);
            //ID设置为null,防止ID冲突。 将来保存的时候 由Db数据库来生成
            subOrderInfo.setId(null);
            //仓库ID
            subOrderInfo.setWareId((String)wareMap.get("wareId"));

            //订单详情表  从原始订单获取出来的订单详情目前长度是2  实际1
            List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList();
            //商品id的集合
            List<String> skuIdList = (List<String>) wareMap.get("skuIds");

            //根据商品id是否相等进行过滤
            List<OrderDetail> orderDetails = orderDetailList.stream().filter(orderDetail -> {
                for (String skuId : skuIdList) {
                    if (skuId.equals(orderDetail.getSkuId().toString())) {
                        return true;  //存在  不过滤掉
                    }
                }
                return false; //不存在  过滤掉了
            }).collect(Collectors.toList());
            //将订单详情集合设置到订单对象中
            subOrderInfo.setOrderDetailList(orderDetails);

            //操作订单表  订单详情表
            saveOrderInfo(subOrderInfo);
            //追加到集合中
            orderInfoList.add(subOrderInfo);
        }
        //更新原始订单表状态为：已拆单
        this.updateOrderStatus(orderInfoOrigin.getId(),OrderStatus.SPLIT,ProcessStatus.SPLIT);

        return orderInfoList;
    }
    //操作订单表  订单详情表
    private void saveOrderInfo(OrderInfo subOrderInfo) {
        //1.保存订单
        orderInfoMapper.insert(subOrderInfo);
        //2.订单详情表
        List<OrderDetail> orderDetailList = subOrderInfo.getOrderDetailList();
        orderDetailList.forEach(orderDetail -> {
            //外键
            orderDetail.setOrderId(subOrderInfo.getId());
            orderDetailMapper.insert(orderDetail);
        });
    }


    private String cacheCartKey(String userId){
        return RedisConst.USER_LOGIN_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
    }
}
